/*
 * Copyright (c) 2025 Industrial Software Feature Database
 */
package com.comac.ins.isfd.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.anwen.mongo.conditions.query.LambdaQueryChainWrapper;
import com.anwen.mongo.model.PageResult;
import com.anwen.mongo.service.impl.ServiceImpl;
import com.anwen.mongo.toolkit.Filters;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.comac.ins.common.core.domain.model.LoginUser;
import com.comac.ins.common.core.exception.base.BaseException;
import com.comac.ins.common.core.utils.MapstructUtils;
import com.comac.ins.common.core.utils.StringUtils;
import com.comac.ins.common.mybatis.core.page.PageQuery;
import com.comac.ins.common.mybatis.core.page.TableDataInfo;
import com.comac.ins.isfd.constant.IsfdMeshOp2Constants;
import com.comac.ins.isfd.constant.MongoDataConstant;
import com.comac.ins.isfd.constant.enums.IsfdMeshOp2CompareObjectBaseRoundEnum;
import com.comac.ins.isfd.constant.enums.IsfdMeshOp2CompareTaskStatusEnum;
import com.comac.ins.isfd.domain.*;
import com.comac.ins.isfd.domain.bo.*;
import com.comac.ins.isfd.domain.chunks.TaskUploadResultVo;
import com.comac.ins.isfd.domain.excel.AutoColumnWidthStyleStrategy;
import com.comac.ins.isfd.domain.excel.CustomMergeStrategy;
import com.comac.ins.isfd.domain.vo.IsfdMeshOp2CompareItemDefaultVo;
import com.comac.ins.isfd.domain.vo.IsfdMeshOp2CompareItemVo;
import com.comac.ins.isfd.domain.vo.IsfdMeshOp2CompareTaskVo;
import com.comac.ins.isfd.mapper.IsfdMeshOp2CompareItemMapper;
import com.comac.ins.isfd.service.IIsfdMeshOP2CompareService;
import com.comac.ins.isfd.service.IIsfdMeshOP2ParseService;
import com.comac.ins.isfd.service.IIsfdMeshOp2CompareItemDefaultService;
import com.mongodb.BasicDBObject;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.result.UpdateResult;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Slf4j
@Service
public class IsfdMeshOP2CompareServiceImpl extends ServiceImpl<IsfdMeshOp2CompareTask> implements IIsfdMeshOP2CompareService {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private MongoClient mongoClient;

    @Autowired
    private IsfdMeshOp2CompareItemMapper isfdMeshOp2CompareItemMapper;

    @Autowired
    private IIsfdMeshOP2ParseService op2ParseService;

    @Autowired
    private IIsfdMeshOp2CompareItemDefaultService isfdMeshOp2CompareItemDefaultService;

    @Override
    public Map<String, List<IsfdMeshOp2CompareElement>> getElementMapList(String filePath) {
        Map<String, List<IsfdMeshOp2CompareElement>> resultMap = new LinkedHashMap<>();

        try (InputStream is = new FileInputStream(filePath);
             Workbook workbook = new XSSFWorkbook(is)) {

            int sheetCount = workbook.getNumberOfSheets();
            if (sheetCount == 0) {
                throw new RuntimeException("Excel 文件中没有 Sheet！");
            }

            for (int sheetIndex = 0; sheetIndex < sheetCount; sheetIndex++) {
                Sheet sheet = workbook.getSheetAt(sheetIndex);
                String sheetName = sheet.getSheetName();

                Iterator<Row> rowIterator = sheet.iterator();

                // 跳过前两行
                if (rowIterator.hasNext()) rowIterator.next(); // 跳过第1行
                if (rowIterator.hasNext()) rowIterator.next(); // 跳过第2行

                // 提取第2行（索引为1）的2A和2C作为x轴和y轴标题
                Row secondRow = sheet.getRow(1);
                String xAxisName, yAxisName;
                if (secondRow != null) {
                    xAxisName = Optional.ofNullable(secondRow.getCell(1))
                        .filter(c -> c.getCellType() == CellType.STRING)
                        .map(Cell::getStringCellValue)
                        .map(String::trim)
                        .orElse("");
                    yAxisName = Optional.ofNullable(secondRow.getCell(3))
                        .filter(c -> c.getCellType() == CellType.STRING)
                        .map(Cell::getStringCellValue)
                        .map(String::trim)
                        .orElse("");
                } else {
                    yAxisName = "";
                    xAxisName = "";
                }

                // 表头
                if (!rowIterator.hasNext()) {
                    throw new IllegalArgumentException("Sheet [" + sheetName + "] 缺少表头！");
                }
                Row headerRow = rowIterator.next();
                List<String> listNames = new ArrayList<>();
                int totalColumns = headerRow.getLastCellNum();

                for (int col = 2; col < totalColumns; col++) {
                    Cell cell = headerRow.getCell(col);
                    if (cell == null || cell.getCellType() != CellType.STRING) {
                        throw new BaseException("Sheet [" + sheetName + "] 表头列名不能为空且必须为字符串！");
                    }
                    listNames.add(cell.getStringCellValue().trim());
                }

                // 使用 Map 存储每个 (分组名 + y列索引) 对应的元素
                Map<String, IsfdMeshOp2CompareElement> elementMap = new LinkedHashMap<>();

                while (rowIterator.hasNext()) {
                    Row row = rowIterator.next();
                    if (isRowEmpty(row, totalColumns)) {
                        continue; // 跳过空行
                    }

                    // 分组名称
                    Cell groupCell = row.getCell(0);
                    if (groupCell == null || groupCell.getCellType() != CellType.STRING) {
                        throw new BaseException("第 " + (row.getRowNum() + 1) + " 行的分组名不能为空且必须为字符串！");
                    }
                    String groupName = groupCell.getStringCellValue().trim();

                    // x轴取值
                    Cell xCell = row.getCell(1);
                    if (xCell == null || xCell.getCellType() != CellType.NUMERIC) {
                        throw new BaseException("第 " + (row.getRowNum() + 1) + " 行的 x 值不是有效数字！");
                    }
                    int xValue = (int) xCell.getNumericCellValue();

                    // y列
                    for (int col = 2; col < totalColumns; col++) {
                        Cell yCell = row.getCell(col);
                        if (yCell != null && yCell.getCellType() == CellType.NUMERIC) {
                            int yValue = (int) yCell.getNumericCellValue();
                            String key = groupName + "#" + col;

                            int finalCol = col;
                            IsfdMeshOp2CompareElement element = elementMap.computeIfAbsent(key, k -> {
                                IsfdMeshOp2CompareElement e = new IsfdMeshOp2CompareElement();
                                e.setGroupName(groupName);
                                e.setListName(listNames.get(finalCol - 2)); // -2 是因为前两列是 groupName 和 x 值
                                e.setValuePair(new LinkedHashMap<>());
                                e.setXAxisLabel(xAxisName);
                                e.setYAxisLabel(yAxisName);
                                return e;
                            });
                            element.getValuePair().put(xValue, yValue);
                        }
                    }
                }
                if (!elementMap.isEmpty()) {
                    List<IsfdMeshOp2CompareElement> resultList = new ArrayList<>(elementMap.values());
                    resultMap.put(sheetName, resultList); // 一个 sheetName 对应一个 list
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("Excel 解析失败：" + e.getMessage(), e);
        }

        if (resultMap.isEmpty()) {
            throw new RuntimeException("节点清单文件未解析出内容！");
        }

        return resultMap;
    }

    private boolean isRowEmpty(Row row, int totalColumns) {
        if (row == null) return true;
        for (int i = 0; i < totalColumns; i++) {
            Cell cell = row.getCell(i);
            if (cell != null && cell.getCellType() != CellType.BLANK) {
                if (cell.getCellType() == CellType.STRING && !cell.getStringCellValue().trim().isEmpty()) {
                    return false;
                }
                if (cell.getCellType() == CellType.NUMERIC) {
                    return false;
                }
            }
        }
        return true;
    }


    /**
     * 对比校验入参
     */
    private void checkParamSet(IsfdMeshOp2CompareTaskBo taskBo) {
        Integer currentStep = taskBo.getCurrentStep();
        String id = taskBo.get_id();
        if (currentStep == 1) {
            List<IsfdMeshOp2CompareObject> stepOne = taskBo.getStepOne();
            if (CollectionUtils.isEmpty(stepOne) || stepOne.size() < 2) {
                throw new BaseException("对比对象至少两个！");
            }
            boolean haveBaseRound = Boolean.FALSE;
            List<String> sectionNumberList = taskBo.getSectionNumbers();
            for (IsfdMeshOp2CompareObject isfdMeshOp2CompareObject : stepOne) {
                if (IsfdMeshOp2CompareObjectBaseRoundEnum.BASE.getValue().equals(isfdMeshOp2CompareObject.getBaseRound())) {
                    haveBaseRound = Boolean.TRUE;
                }
                String sectionNumbers = String.join(",", sectionNumberList);
                // 重新给部段赋值
                isfdMeshOp2CompareObject.setSectionNumbers(sectionNumbers);
            }
            if (!haveBaseRound) {
                throw new BaseException("对比对象中不存在基本轮次，请设置！");
            }
        }

        if (currentStep == 2) {
            if (StringUtils.isBlank(id)) {
                throw new BaseException("主键id不能为空");
            }
            List<IsfdMeshOp2CompareItemRef> stepTwo = taskBo.getStepTwo();
            if (CollectionUtils.isEmpty(stepTwo)) {
                throw new BaseException("对比条目列表不能为空！");
            }
            // 使用HashSet去重（保留顺序）
            Set<String> seenKeys = new HashSet<>();
            List<IsfdMeshOp2CompareItemRef> distinctList = new ArrayList<>();
            for (IsfdMeshOp2CompareItemRef item : stepTwo) {
                String compositeKey = item.getType() + "|" + item.getId();
                if (!seenKeys.contains(compositeKey)) {
                    seenKeys.add(compositeKey);
                    distinctList.add(item);
                }
            }
            taskBo.setStepTwo(distinctList);
        }

        if (currentStep == 3) {
            if (StringUtils.isBlank(id)) {
                throw new BaseException("主键id不能为空");
            }
            IsfdMeshOp2UnitNodeList stepThree = taskBo.getStepThree();
            if (stepThree == null || StringUtils.isBlank(stepThree.getTemplateUploadUrl())) {
                throw new BaseException("单元节点上传模版不能为空！");
            }
        }
    }

    @Override
    public IsfdMeshOp2CompareTaskVo createOP2CompareTask(IsfdMeshOp2CompareTaskBo taskBo, LoginUser loginUser) {
        // 1.校验
        checkParamSet(taskBo);

        Integer currentStep = taskBo.getCurrentStep();
        // 2.确认填写完成的最大步骤
        Integer maxStep = 1;
        if (currentStep >= maxStep) {
            maxStep = currentStep;
        }

        // 3.填充task任务信息
        IsfdMeshOp2CompareTask task = MapstructUtils.convert(taskBo, IsfdMeshOp2CompareTask.class);
        task.setStatus(maxStep == 3 ?
            IsfdMeshOp2CompareTaskStatusEnum.IN_PROGRESS.getValue() :
            IsfdMeshOp2CompareTaskStatusEnum.EDIT.getValue());
        task.setMaxStep(maxStep);
        Date currentDate = new Date();
        if (taskBo.get_id() == null) {
            task.setCreateBy(loginUser.getUserId());
            task.setCreateTime(currentDate);
        }
        task.setUpdateBy(loginUser.getUserId());
        task.setUpdateTime(currentDate);
        this.saveOrUpdate(task);

        // 4.提交异步任务
        if (maxStep == 3) {
            CompletableFuture.runAsync(() -> saveCompareResult(task, task.get_id()));
        }

        // 5.封装返回
        return MapstructUtils.convert(task, IsfdMeshOp2CompareTaskVo.class);
    }

    @Override
    public void saveCompareResult(IsfdMeshOp2CompareTask task, String taskIdStr) {
        try {
            // 找到要对比的op2
            List<IsfdMeshOp2CompareObject> op2CompareObjects = task.getStepOne();
            if (CollectionUtils.isEmpty(op2CompareObjects)) {
                throw new BaseException("分析对象不能为空！");
            }
            // 对比条目
            List<IsfdMeshOp2CompareItemRef> op2CompareItems = task.getStepTwo();
            if (CollectionUtils.isEmpty(op2CompareItems)) {
                throw new BaseException("对比条目不能为空！");
            }
            // 读取excel获取节点清单
            String elementMapListExcelUrl = task.getStepThree().getTemplateUploadUrl();
            Map<String, List<IsfdMeshOp2CompareElement>> elementListMap = getElementMapList(elementMapListExcelUrl);

            // 按对比条目分批比较
            List<IsfdMeshOp2CompareResultItem> resultItems = new ArrayList<>();
            for (IsfdMeshOp2CompareItemRef op2CompareItem : op2CompareItems) {
                // 处理matchkey多个的情况
                String[] items = op2CompareItem.getMatchKey().split(",");

                // 对比节点清单分组列表
                List<IsfdMeshOp2CompareResultElementGroup> compareResultElementGroups = new ArrayList<>();

                List<IsfdMeshOp2CompareElement> elementListOfOneSheet = elementListMap.get(op2CompareItem.getItemName());
                if (CollectionUtils.isEmpty(elementListOfOneSheet)) {
                    throw new BaseException(op2CompareItem.getItemName() + "的节点清单为空！");
                }
                Map<String, List<IsfdMeshOp2CompareElement>> elementGroupMap = elementListOfOneSheet.stream().collect(
                    Collectors.groupingBy(IsfdMeshOp2CompareElement::getGroupName));

                // 分组节点清单
                for (Map.Entry<String, List<IsfdMeshOp2CompareElement>> entry : elementGroupMap.entrySet()) {
                    IsfdMeshOp2CompareResultElementGroup compareResultElementGroup = new IsfdMeshOp2CompareResultElementGroup();
                    compareResultElementGroup.setGroupName(entry.getKey());
                    compareResultElementGroup.setXAxisLabel(entry.getValue().get(0).getXAxisLabel());
                    compareResultElementGroup.setYAxisLabel(entry.getValue().get(0).getYAxisLabel());

                    // 根据listName再group一把
                    Map<String, List<IsfdMeshOp2CompareElement>> elementGroupListMap = entry.getValue().stream().collect(
                        Collectors.groupingBy(IsfdMeshOp2CompareElement::getListName)
                    );
                    if (CollectionUtils.isEmpty(elementGroupListMap)) {
                        throw new BaseException("节点清单中没有对应数据！name:" + entry.getKey());
                    }

                    List<IsfdMeshOp2CompareResultData> resultDatas = new ArrayList<>();
                    for (IsfdMeshOp2CompareObject op2CompareObject : op2CompareObjects) {

                        String listName = generateListName(op2CompareObject);

                        List<IsfdMeshOp2CompareElement> elementList = elementGroupListMap.entrySet().stream()
                            .filter(e -> e.getKey().contains(listName))
                            .map(Map.Entry::getValue)
                            .findFirst()
                            .orElseThrow(() -> new RuntimeException("未找到包含 '" + listName + "' 的 groupName！"));

                        Map<Integer, Integer> elementValuePair;
                        try {
                            elementValuePair = elementList.stream()
                                .flatMap(element -> element.getValuePair().entrySet().stream())
                                .collect(Collectors.toMap(
                                    Map.Entry::getKey,
                                    Map.Entry::getValue
                                ));
                        } catch (IllegalStateException e) {
                            throw new RuntimeException("发现重复的 x 值！", e);
                        }

                        // 找出对应数据
                        // 初始化一个合并后的 resultData 对象
                        IsfdMeshOp2CompareResultData mergedResultData = new IsfdMeshOp2CompareResultData();
                        mergedResultData.setIsBaseRound(op2CompareObject.getBaseRound() == 1);
                        mergedResultData.setName(listName);

                        List<IsfdMeshOp2CompareResultDataDetail> mergedDataList = new ArrayList<>();

                        for (String item : items) {
                            String[] parts = splitByLastDot(item);
                            String resultName = parts[0];
                            String subResultName = parts[1];

                            if (StringUtils.isBlank(resultName) || StringUtils.isBlank(subResultName)) {
                                throw new BaseException("结果名称或分力名称为空！");
                            }

                            IsfdMeshOp2QueryBo queryBo = new IsfdMeshOp2QueryBo();
                            queryBo.setResultName(resultName);
                            queryBo.setSubResultName(subResultName);
                            queryBo.setUploadId(op2CompareObject.getUploadId());
                            queryBo.setElementPairs(elementValuePair);

                            // 查询子结果
                            IsfdMeshOp2CompareResultData subResult = op2ParseService.getResultData(queryBo);

                            // 合并 dataList
                            if (subResult.getDataDetailList() != null) {
                                mergedDataList.addAll(subResult.getDataDetailList());
                            }
                        }

                        mergedResultData.setDataDetailList(mergedDataList);

                        resultDatas.add(mergedResultData);

                    }

                    // 比较数据，计算差值比
                    calculatePercentDifferences(resultDatas);


                    // 存储结果
                    compareResultElementGroup.setDataList(resultDatas);
                    compareResultElementGroups.add(compareResultElementGroup);
                }

                // 对比结果，条目名称
                IsfdMeshOp2CompareResultItem resultItem = new IsfdMeshOp2CompareResultItem();
                resultItem.setItemName(op2CompareItem.getItemName());
                resultItem.setElementGroups(compareResultElementGroups);
                resultItem.setMatchKey(op2CompareItem.getMatchKey());
                resultItems.add(resultItem);
            }

            // 构造对比结果
            IsfdMeshOp2CompareResult result = new IsfdMeshOp2CompareResult();
            result.set_id(task.get_id());
            result.setResultItems(resultItems);
            result.setTaskName(task.getTaskName());
            result.setSectionNumbers(task.getSectionNumbers());
            result.setComparedObjects(task.getStepOne());

            // 保存对比结果
            saveCompareResultToMongo(result);

            // 更新任务状态为完成
            updateTaskStatus(taskIdStr, IsfdMeshOp2CompareTaskStatusEnum.COMPLETED, "");

        } catch (Exception e) {
            log.error("op2结果提取失败", e);
            String message = e.getMessage();
            updateTaskStatus(taskIdStr, IsfdMeshOp2CompareTaskStatusEnum.FAILED, message);
        }
    }


    private void saveCompareResultToMongo(IsfdMeshOp2CompareResult result) {
        if (result == null) {
            log.error("对比分析结果不能为空！");
            throw new BaseException("对比分析结果不能为空！");
        }
        MongoDatabase database = mongoClient.getDatabase(MongoDataConstant.OP2_DATABASE);

        Document document = new Document();
        mongoTemplate.getConverter().write(result, document);
        document.remove("_class");  // 移除 "_class" 字段
        database.getCollection(MongoDataConstant.MESH_OP2_COMPARE_RESULT_TABLE_NAME).insertOne(document);
    }

    private static String[] splitByLastDot(String input) {
        int lastDot = input.lastIndexOf(".");
        if (lastDot == -1) {
            return new String[]{input, ""};
        }
        return new String[]{
            input.substring(0, lastDot),
            input.substring(lastDot + 1)
        };
    }

    private String generateListName(IsfdMeshOp2CompareObject op2CompareObject) {
        String modelNumber = op2CompareObject.getModelNumber();
        String batchNumber = op2CompareObject.getBatchNumber();
        String sectionNumber = op2CompareObject.getSectionNumbers();
        String roundNumber = op2CompareObject.getRoundNumber();
        if (StringUtils.isBlank(modelNumber) || StringUtils.isBlank(batchNumber) ||
            StringUtils.isBlank(sectionNumber) || StringUtils.isBlank(roundNumber)) {
            throw new BaseException("对比对象信息不全！");
        }
        return String.join("-", modelNumber, batchNumber, sectionNumber, roundNumber);
    }

    private void calculatePercentDifferences(List<IsfdMeshOp2CompareResultData> resultDatas) {
        IsfdMeshOp2CompareResultData baseRoundResultData = resultDatas.stream().filter(
            r -> r.getIsBaseRound().equals(true)
        ).findFirst().orElse(null);
        if (baseRoundResultData == null) {
            throw new BaseException("没有找到基准轮次！");
        }

        Map<Integer, IsfdMeshOp2CompareResultDataDetail> baseRoundDetails = baseRoundResultData.getDataDetailList().stream()
            .collect(Collectors.toMap(
                IsfdMeshOp2CompareResultDataDetail::getXIndex,
                detail -> detail // 或 Function.identity()
            ));

        List<IsfdMeshOp2CompareResultData> compareRounds = resultDatas.stream()
            .filter(r -> !Boolean.TRUE.equals(r.getIsBaseRound()))
            .toList();

        for (IsfdMeshOp2CompareResultData compareResultData : compareRounds) {
            Map<Integer, IsfdMeshOp2CompareResultDataDetail> resultDataDetails = compareResultData.getDataDetailList().stream()
                .collect(Collectors.toMap(
                    IsfdMeshOp2CompareResultDataDetail::getXIndex,
                    detail -> detail // 或 Function.identity()
                ));

            for (Integer xIndex : resultDataDetails.keySet()) {
                IsfdMeshOp2CompareResultDataDetail baseRoundDetail = baseRoundDetails.get(xIndex);
                IsfdMeshOp2CompareResultDataDetail currentDataDetail = resultDataDetails.get(xIndex);

                // 获取数据
                Float maxDataBaseRound = baseRoundDetail.getMaxData();
                Float minDataBaseRound = baseRoundDetail.getMinData();
                Float maxDataCurrentRound = currentDataDetail.getMaxData();
                Float minDataCurrentRound = currentDataDetail.getMinData();

                // 计算区别
                Float maxDataPercentDiff = (maxDataCurrentRound - maxDataBaseRound) / maxDataBaseRound;
                Float minDataPercentDiff = (minDataCurrentRound - minDataBaseRound) / minDataBaseRound;

                // 设置值
                currentDataDetail.setMaxDataPercentDiff(maxDataPercentDiff);
                currentDataDetail.setMinDataPercentDiff(minDataPercentDiff);
            }
        }

    }

    public void updateTaskStatus(String taskId, IsfdMeshOp2CompareTaskStatusEnum status, String message) {

        Map<String, Object> update = new HashMap<>();
        update.put("status", status.getValue());
        if (StringUtils.isNotBlank(message)) {
            update.put("message", message.length() >= 255 ? message.substring(0, 255) : message);
        }
        if (StringUtils.isBlank(taskId)) {
            throw new BaseException("任务 ID 不能为空！");
        }

        MongoDatabase database = mongoClient.getDatabase(MongoDataConstant.DB_NAME);
        String taskCollection = MongoDataConstant.MESH_OP2_COMPARE_TASK_TABLE_NAME;
        MongoCollection<Document> collection = database.getCollection(taskCollection);

        // 执行更新操作
        Document query = new Document("_id", new ObjectId(taskId));
        Document updateDoc = new Document("$set", new Document(update));

        UpdateResult result = collection.updateOne(query, updateDoc);

        if (result.getModifiedCount() == 0) {
            log.warn("任务 ID {} 未找到或状态未变更", taskId);
        }
    }


    private IsfdMeshOp2Info getParsedOp2Info(String objectId) {
        String collectionName = MongoDataConstant.OP2_PARSE_INFO_COLLECTION;
        MongoDatabase database = mongoClient.getDatabase(MongoDataConstant.OP2_DATABASE);
        if (!collectionExists(database, collectionName)) {
            log.error("表未创建！: " + collectionName);
            throw new BaseException("表未创建！: " + collectionName);
        }
        BasicDBObject query = new BasicDBObject();
        query.put("objectId", objectId);
        MongoCollection<Document> collection = database.getCollection(collectionName);
        Document document = collection.find(query).first();
        if (document == null) {
            throw new BaseException("未找到相关OP2解析信息！");
        }
        return mongoTemplate.getConverter().read(IsfdMeshOp2Info.class, document);
    }

    @Override
    public TableDataInfo<IsfdMeshOp2CompareTaskVo> queryPageList(IsfdMeshOp2CompareQueryBo queryBo) {
        PageQuery pageQuery = queryBo.getPageQuery();
        LambdaQueryChainWrapper<IsfdMeshOp2CompareTask> queryChainWrapper = this.lambdaQuery();
        if (StringUtils.isNotBlank(queryBo.getSectionNumber())) {
            queryChainWrapper.in(IsfdMeshOp2CompareTask::getSectionNumbers, queryBo.getSectionNumber());
        }
        if (StringUtils.isNotBlank(queryBo.getSectionName())) {
            queryChainWrapper.in(IsfdMeshOp2CompareTask::getSectionNames, queryBo.getSectionName());
        }
        if (queryBo.getEndCreateTime() != null && queryBo.getStartCreateTime() != null) {
            queryChainWrapper.gte(IsfdMeshOp2CompareTask::getCreateTime, queryBo.getStartCreateTime());
            queryChainWrapper.lte(IsfdMeshOp2CompareTask::getCreateTime, queryBo.getEndCreateTime());
        }
        queryChainWrapper.orderByDesc(IsfdMeshOp2CompareTask::getCreateTime);
        PageResult<IsfdMeshOp2CompareTask> pageResult = this.page(queryChainWrapper, pageQuery.getPageNum(), pageQuery.getPageSize());
        long totalSize = pageResult.getTotalSize();
        if (totalSize <= 0) {
            return TableDataInfo.build();
        }

        List<IsfdMeshOp2CompareTaskVo> contentData = MapstructUtils.convert(pageResult.getContentData(), IsfdMeshOp2CompareTaskVo.class);
        return TableDataInfo.buildToPageMemoryLimit(Boolean.FALSE, contentData, pageQuery.getPageNum(), pageQuery.getPageSize(), totalSize);
    }

    @Override
    public IsfdMeshOp2CompareTaskVo queryResultDetail(String id) {
        IsfdMeshOp2CompareTask task = this.getById(id);
        if (task == null) {
            return null;
        }
        return MapstructUtils.convert(task, IsfdMeshOp2CompareTaskVo.class);
    }

    @Override
    public IsfdMeshOp2CompareResult getCompareReport(String id) {
        MongoDatabase database = mongoClient.getDatabase(MongoDataConstant.OP2_DATABASE);
        Document doc = database
            .getCollection(MongoDataConstant.MESH_OP2_COMPARE_RESULT_TABLE_NAME)
            .find(Filters.eq("_id", new ObjectId(id)))
            .first();
        if (doc == null) {
            return null;
        }
        return mongoTemplate.getConverter().read(IsfdMeshOp2CompareResult.class, doc);
    }

    @Override
    public Boolean deleteTask(String id) {
        // 删除对比结果
        MongoDatabase database = mongoClient.getDatabase(MongoDataConstant.OP2_DATABASE);
        MongoCollection<Document> collection = database.getCollection(MongoDataConstant.MESH_OP2_COMPARE_RESULT_TABLE_NAME);
        collection.findOneAndDelete(Filters.eq("_id", new ObjectId(id)));
        // 删除对比任务
        return this.removeById(id);
    }

    @Override
    @Transactional
    public Boolean addCompareItem(List<IsfdMeshOp2CompareItemBo> compareItemBoList) {
        if (CollectionUtils.isEmpty(compareItemBoList)) {
            return Boolean.FALSE;
        }

        // 递归新增返回
        for (IsfdMeshOp2CompareItemBo rootItemBo : compareItemBoList) {
            // 根节点默认 parentId = 0，level = 1
            rootItemBo.setParentId(0L);
            rootItemBo.setLevel(1);
            insertWithChildren(rootItemBo);
        }
        return Boolean.TRUE;
    }

    /**
     * 递归插入当前条目及其子条目
     */
    private void insertWithChildren(IsfdMeshOp2CompareItemBo compareItemBo) {
        // 插入当前条目
        isfdMeshOp2CompareItemMapper.addCompareItem(compareItemBo);

        // 插入子条目
        List<IsfdMeshOp2CompareItemBo> children = compareItemBo.getChildCompareItemBoList();
        if (!CollectionUtils.isEmpty(children)) {
            for (IsfdMeshOp2CompareItemBo child : children) {
                child.setParentId(compareItemBo.getId());
                child.setLevel(compareItemBo.getLevel() + 1);
                insertWithChildren(child);
            }
        }
    }

    public List<IsfdMeshOp2CompareItemVo> getCompareItemList() {
        // 这里可以调用 DAO 层或者直接从缓存获取数据
        return isfdMeshOp2CompareItemMapper.selectVoList();
    }

    public List<IsfdMeshOp2CompareItemVo> getCompareItemTree() {
        // 递归生成树形结构
        List<IsfdMeshOp2CompareItemVo> rootItemList = isfdMeshOp2CompareItemMapper.selectVoList(new LambdaQueryWrapper<IsfdMeshOp2CompareItem>()
            .eq(IsfdMeshOp2CompareItem::getParentId, 0l));
        // 遍历每个根条目，加载其子条目
        for (IsfdMeshOp2CompareItemVo rootItem : rootItemList) {
            loadChildItems(rootItem);
        }
        return rootItemList;
    }

    @Override
    public TaskUploadResultVo upload(MultipartFile file, String taskId) {
        // 1.存储文件
        String fileUrl;
        try {
            Path path = Paths.get(IsfdMeshOp2Constants.UPLOAD_COMPARE_PREFIX, taskId, file.getOriginalFilename());
            Files.createDirectories(path.getParent());
            file.transferTo(path);
            fileUrl = path.toString();
        } catch (IOException e) {
            // 处理文件上传异常
            log.error("文件上传失败！", e);
            throw new RuntimeException("文件上传失败", e);
        }
        TaskUploadResultVo taskUploadResultVo = new TaskUploadResultVo();
        taskUploadResultVo.setTaskId(taskId);
        taskUploadResultVo.setFileUrl(fileUrl);
        return taskUploadResultVo;
    }

    @Override
    public List<IsfdMeshOp2CompareItemDefaultVo> listDefaultCompareItems() {
        IsfdMeshOp2CompareItemDefaultBo bo = new IsfdMeshOp2CompareItemDefaultBo();
        return isfdMeshOp2CompareItemDefaultService.queryList(bo);
    }

    private void loadChildItems(IsfdMeshOp2CompareItemVo parentItem) {
        // 获取该父级条目的子条目
        List<IsfdMeshOp2CompareItemVo> childItemList = isfdMeshOp2CompareItemMapper.selectVoList(new LambdaQueryWrapper<IsfdMeshOp2CompareItem>()
            .eq(IsfdMeshOp2CompareItem::getParentId, parentItem.getId()));
        if (!CollectionUtils.isEmpty(childItemList)) {
            parentItem.setChildCompareItemVoList(childItemList);
            // 递归加载每个子条目的子条目
            for (IsfdMeshOp2CompareItemVo childItem : childItemList) {
                loadChildItems(childItem);
            }
        }
    }

    @Override
    public void getExcelTemplate(String id, HttpServletResponse response) {
        IsfdMeshOp2CompareTaskVo taskVo = this.queryResultDetail(id);
        if (taskVo == null || CollectionUtils.isEmpty(taskVo.getStepOne()) || CollectionUtils.isEmpty(taskVo.getStepTwo())) {
            throw new BaseException("对比解析任务不能为空 或者 对比对象/对比项不能为空");
        }

        // 生成表头的通用部分
        List<String> tableNameList = new ArrayList<>();
        String sectionNumbers = String.join(",", taskVo.getSectionNumbers());
        for (IsfdMeshOp2CompareObject compareObject : taskVo.getStepOne()) {
            String modelNumber = compareObject.getModelNumber();
            String batchNumber = compareObject.getBatchNumber();
            String roundNumber = compareObject.getRoundNumber();
            String tableName = modelNumber + "-" + batchNumber + "-" + sectionNumbers + "-" + roundNumber + "的\n单元/节点清单";
            tableNameList.add(tableName);
        }

        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            String fileName = URLEncoder.encode("单元节点清单模版", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
            response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

            ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream())
                .inMemory(false)
                .registerWriteHandler(new CustomMergeStrategy())  // 自定义合并策略
                .registerWriteHandler(new AutoColumnWidthStyleStrategy())  // 自动列宽
                .build();

            // 每个 compareItem 创建一个 sheet
            for (IsfdMeshOp2CompareItemRef compareItem : taskVo.getStepTwo()) {
                String itemName = compareItem.getItemName();
                if (StringUtils.isBlank(itemName)) {
                    throw new BaseException("对比条目为空，请检查！");
                }

                List<List<String>> data = new ArrayList<>();
                // 第一行：注释
                data.add(Arrays.asList("注：表格内数据不能有空行！", "", "", "", "", ""));
                // 第二行：定义 X/Y轴
                data.add(Arrays.asList("定义X轴名称", "", "定义Y轴名称", "", "", ""));
                // 第三行：正式表头
                List<String> headerRow = new ArrayList<>();
                headerRow.add("分组名称");
                headerRow.add("X轴取值");
                headerRow.addAll(tableNameList);
                data.add(headerRow);

                WriteSheet writeSheet = EasyExcel.writerSheet(itemName)
                    .needHead(false)  // 不使用默认表头，用自定义数据控制
                    .build();
                excelWriter.write(data, writeSheet);
            }

            excelWriter.finish();
        } catch (IOException e) {
            log.error("生成Excel模板失败！", e);
            throw new BaseException("生成Excel模板失败");
        }
    }

    @Override
    public void getExcelSample(String id, HttpServletResponse response) {
        IsfdMeshOp2CompareTaskVo taskVo = this.queryResultDetail(id);
        if (taskVo == null || CollectionUtils.isEmpty(taskVo.getStepOne()) || CollectionUtils.isEmpty(taskVo.getStepTwo())) {
            throw new BaseException("对比解析任务不能为空 或者 对比对象/对比项不能为空");
        }
        // 所有对比对象
        String sectionNumbers = String.join(",", taskVo.getSectionNumbers());
        List<IsfdMeshOp2CompareObject> compareObjectList = taskVo.getStepOne();
        Map<String, Map<String, List<Integer>>> sampleElementsMap = new HashMap<>();
        for (IsfdMeshOp2CompareObject compareObject : compareObjectList) {
//            if(sampleElementsMap.containsKey(compareObject.getFileName())){
//                continue;
//            }
            String uploadId = compareObject.getUploadId();
            Map<String, List<Integer>> sampleElements = op2ParseService.getSampleElements(uploadId, 1, 1000);

            // sheet页名称
            String modelNumber = compareObject.getModelNumber();
            String batchNumber = compareObject.getBatchNumber();
            String roundNumber = compareObject.getRoundNumber();
            String sheetName = modelNumber + "-" + batchNumber + "-" + sectionNumbers + "-" + roundNumber;
            // String sheetName = compareObject.getFileName();
            sampleElementsMap.put(sheetName, sampleElements);
        }


        // 保存到excel
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            String fileName = URLEncoder.encode("单元节点id样例", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
            response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

            ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream())
                .inMemory(false)
                .registerWriteHandler(new AutoColumnWidthStyleStrategy())  // 自动列宽
                .build();

            // 每个 compareItem 创建一个 sheet
            for (String sheetName : sampleElementsMap.keySet()) {
                Map<String, List<Integer>> sampleElements = sampleElementsMap.get(sheetName);

                // 构造数据行：以最长列的长度为基准，逐行收集每列数据
                int maxRow = sampleElements.values().stream().mapToInt(List::size).max().orElse(0);
                List<List<Object>> dataRows = new ArrayList<>();

                for (int i = 0; i < maxRow; i++) {
                    List<Object> row = new ArrayList<>();
                    for (String key : sampleElements.keySet()) {
                        List<Integer> values = sampleElements.get(key);
                        row.add(i < values.size() ? values.get(i) : null);
                    }
                    dataRows.add(row);
                }

                // 表头
                List<List<String>> head = new ArrayList<>();
                for (String key : sampleElements.keySet()) {
                    head.add(Collections.singletonList(key));
                }

                WriteSheet writeSheet = EasyExcel.writerSheet(sheetName)
                    .head(head)
                    .build();

                excelWriter.write(dataRows, writeSheet);
            }

            excelWriter.finish();
        } catch (IOException e) {
            log.error("生成Excel模板失败！", e);
            throw new BaseException("生成Excel模板失败");
        }

    }


    private boolean collectionExists(MongoDatabase database, String collectionName) {
        for (String name : database.listCollectionNames()) {
            if (name.equals(collectionName)) {
                return true;
            }
        }
        return false;
    }
}
